package com.spring.security.client.browser.config;

import com.spring.security.core.authorize.AuthorizeConfigManager;
import com.spring.security.core.authtication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.spring.security.core.config.FormAuthenticationConfig;
import com.spring.security.core.properties.SecurityConstants;
import com.spring.security.core.properties.SecurityProperties;
import com.spring.security.core.validate.config.ValidateCodeSecurityConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;

import javax.sql.DataSource;

/**
 * 浏览器环境下安全配置主类
 *
 * @author seabed_moon
 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {


    private final SecurityProperties securityProperties;

    private final DataSource dataSource;

    private final UserDetailsService userDetailsService;

    private final SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;

    private final FormAuthenticationConfig formAuthenticationConfig;

    private final ValidateCodeSecurityConfig validateCodeSecurityConfig;

    private final InvalidSessionStrategy invalidSessionStrategy;

    private final SessionInformationExpiredStrategy sessionInformationExpiredStrategy;

    private final LogoutSuccessHandler logoutSuccessHandler;

    private final AuthorizeConfigManager authorizeConfigManager;

    public BrowserSecurityConfig(SecurityProperties securityProperties, DataSource dataSource, UserDetailsService userDetailsService, SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig, FormAuthenticationConfig formAuthenticationConfig, ValidateCodeSecurityConfig validateCodeSecurityConfig, InvalidSessionStrategy invalidSessionStrategy, SessionInformationExpiredStrategy sessionInformationExpiredStrategy, LogoutSuccessHandler logoutSuccessHandler, AuthorizeConfigManager authorizeConfigManager) {
        this.securityProperties = securityProperties;
        this.dataSource = dataSource;
        this.userDetailsService = userDetailsService;
        this.smsCodeAuthenticationSecurityConfig = smsCodeAuthenticationSecurityConfig;
        this.formAuthenticationConfig = formAuthenticationConfig;
        this.validateCodeSecurityConfig = validateCodeSecurityConfig;
        this.invalidSessionStrategy = invalidSessionStrategy;
        this.sessionInformationExpiredStrategy = sessionInformationExpiredStrategy;
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.authorizeConfigManager = authorizeConfigManager;
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {


        //表单登录配置
        formAuthenticationConfig.configure(http);

        http
                //校验码相关安全配置
                .apply(validateCodeSecurityConfig)
                .and()
                //短信验证码登录安全配置
                .apply(smsCodeAuthenticationSecurityConfig)
                .and()
                .sessionManagement()
                .invalidSessionStrategy(invalidSessionStrategy)
                .maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
                .maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())
                .expiredSessionStrategy(sessionInformationExpiredStrategy)
                .and()
                .and()
                .logout()
                .logoutUrl(SecurityConstants.DEFAULT_SIGN_OUT_PROCESSING_URL_FORM)
                .logoutSuccessHandler(logoutSuccessHandler)
                .deleteCookies(SecurityConstants.DEFAULT_PARAMETER_NAME_SESSIONS)
                .and()
                .csrf().disable();
        if (securityProperties.getBrowser().getRememberMe()) {
            http.rememberMe()
                    .tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
                    .userDetailsService(userDetailsService)
                    .and()
                    .csrf().disable();
        }

        authorizeConfigManager.config(http.authorizeRequests());
    }
}
